/*
** malloc.c for malloc in /home/newin/malloc
**
** Made by
** Login  <@epitech.eu>
**
** Started on  Wed Jan 30 23:13:12 2013
** Last update Thu Feb 07 16:15:45 2013 vincent leroy
*/

#include <string.h>
#include <pthread.h>
#include "malloc.h"
#include "bsr.h"

pthread_mutex_t __mutex1 = PTHREAD_MUTEX_INITIALIZER;

static int _pagesize;

int		_getpagesize()
{
    if (_pagesize == 0)
        _pagesize = getpagesize();
    return _pagesize;
}

void*			__malloc(header_t **h, long size, size_t length)
{
    header_t	*cur;
    *h = __getSbrk0() ? __getSbrk0() : sbrk(0);
    if (brk(ADD(*h, size)) == -1)
        return NULL;
    __setSbrk0(ADD(*h, size));
    (*h)->size = length;
    for (cur = __getFirstAllocated(); cur && cur->next; cur = cur->next);
    (*h)->back = cur;
    (*h)->next = NULL;
    if (cur)
        cur->next = *h;
    return *h;
}

void*			malloc(size_t length)
{
    header_t    *h;
    long		size;

    LOCK;
#ifdef __UNIX_LIKE_ALLOCATION
    size = bsr(length + sizeof(header_t));
#else
    size = ((length + sizeof(header_t)) / _getpagesize() + 1) * _getpagesize();
#endif
    if ((h = __searchFree(length)) == NULL)
    {
        if (__malloc(&h, size, length) == NULL)
            return NULL;
    }
    else
        h->size = length;
    if (!__getFirstAllocated())
        __setFirstAllocated(h);
    UNLOCK;
    return ADD(h, sizeof(header_t));
}

void*			realloc(void *ptr, size_t size)
{
    void		*new;
    header_t	*tmp;

    if (ptr)
    {
        tmp = SUB(ptr, sizeof(header_t));
        new = tmp->next ? tmp->next : __getSbrk0();
        if (((unsigned long)new - (unsigned long)ptr) > size)
        {
            tmp->size = size;
            return ptr;
        }
    }
    new = malloc(size);
    if (new && ptr)
    {
        tmp = SUB(ptr, sizeof(header_t));
        bcopy(ptr, new, (size_t)tmp->size > size ? size : (size_t)tmp->size);
        free(ptr);
    }
    return new;
}

void*		calloc(size_t nmemb, size_t size)
{
    void 	*new;

    if ((new = malloc(nmemb * size)) == NULL)
        return NULL;
    memset(new, 0, nmemb * size);
    return new;
}
